﻿using System;
using Qadir.Collections.Generic;
using System.Collections.Generic;
using System.Net;
using System.IO;

namespace Qadir.Net
{
    /// <summary>
    /// An wrapper around classes within the System.Net namespace that supports cookies, among other now-common Web features.
    /// </summary>
    public partial class Internet
    {
        /// <summary>
        /// A cookie-aware wrapper around a HttpWebRequest instance that is used to access the Web.
        /// </summary>
        public class Requestor : QadirObject<HttpWebRequest>
        {
            private Requestor(HttpWebRequest request)
                :base(request)
            {
                BaseObject = request;
            }

            /// <summary>
            /// Any HTTP cookies associated with this instance.
            /// </summary>
            public Manager<Cookie> Cookies { get; set; }

            /// <summary>
            /// The underlying HttpWebRequest object.
            /// </summary>
            public HttpWebRequest UnderlyingRequest { get { return BaseObject; } }

            /// <summary>
            /// Creates a new Requestor for the specified URL.
            /// </summary>
            /// <param name="url">The Uniform Resource Locator of the resource which you are trying to access.</param>
            /// <param name="method">The HTTP method that will be used for this instance.</param>
            /// <returns>Returns an initialized Requestor object, ready to perform your request.</returns>
            public static Requestor Create(string url, string method = WebRequestMethods.Http.Get)
            {
                Requestor result = new Requestor((HttpWebRequest)WebRequest.Create(url));
                result.BaseObject.Method = method;
                return result;
            }

            /// <summary>
            /// Creates a new Requestor for the specified URL, using the HTTP POST method, and writes values to its request stream.
            /// </summary>
            /// <param name="url">The Uniform Resource Locator of the resource which you are trying to access.</param>
            /// <returns>Returns an initialized Requestor object, ready to perform your request.</returns>
            public static Requestor CreatePost(string url, IDictionary<string,string> values)
            {
                Requestor result = Requestor.Create(url, WebRequestMethods.Http.Post);
                string valueString = string.Empty;
                foreach (string key in values.Keys)
                {
                    valueString += string.Format("{0}={1}&", key, values[key]);
                }
                valueString = valueString.TrimEnd('&');
                using (Stream ms = result.BaseObject.GetRequestStream())
                {
                    using (StreamWriter sw = new StreamWriter(ms))
                    {
                        sw.Write(valueString);
                    }
                }
                result.BaseObject.ContentLength = valueString.Length;
                return result;
            }

            /// <summary>
            /// Gets an HTTP header from this instance.
            /// </summary>
            /// <param name="header">The header to be retrieved.</param>
            /// <returns>Returns the value of the header.</returns>
            public string GetHeader(string header)
            {
                string result = GetProperty<string>(header);
                if (result == default(string))
                    return GetProperty<string>("Headers", true, new object[] { header });
                else
                    return result;
            }

            /// <summary>
            /// Sends the request and receives a response. Supports asynchronicity. The calling thread will block until a response is received.
            /// </summary>
            /// <param name="asynchronous">A boolean value determining if the request should be sent on a new thread.</param>
            /// <returns>Returns the response of the web server hosting the desired resource.</returns>
            public Responder GetResponder(bool asynchronous = true)
            {
                return new Responder(GetResponse(asynchronous));
            }

            /// <summary>
            /// Sends the request and receives a response. Supports asynchronicity and thread blocking.
            /// </summary>
            /// <param name="asynchronous">A boolean value determining if the request should be sent on a new thread.</param>
            /// <param name="blocking">A boolean value determining if the current thread should block until the operation is completed. To access a populated HttpWebResponse object post-request, this value must be set to true.</param>
            /// <returns>Returns the response of the web server hosting the desired resource.</returns>
            public HttpWebResponse GetResponse(bool asynchronous = true, bool blocking = true)
            {
                if (asynchronous)
                    return (HttpWebResponse)Async.Go<WebResponse>(BaseObject.GetResponse, blocking);
                else
                    return (HttpWebResponse)BaseObject.GetResponse();
            }

            /// <summary>
            /// Sets an HTTP header on this instance.
            /// </summary>
            /// <param name="header">The header to be set.</param>
            /// <param name="value">The value of the header.</param>
            public void SetHeader(string header, string value)
            {
                if (!SetProperty<string>(header, value))
                    SetProperty("Headers", value, true, new object[] { header });
            }
        }
    }
}
